(load "swarm.scm")

;; helper to make lists containing a factorial combination of
;; parameters for input into the model
(define comb
  (lambda (ls . ls*)
    (if (null? ls*)
        (map list ls)
        (let ([d (apply comb ls*)])
          (apply append (map (lambda (x)
                               (map (lambda (y)
                                      (cons x y))
                                    d))
                             ls))))))

(define run-single-experiment
  (lambda (neighw social r23-min)
    (let* ([d-max 100.0]
           [min-v #(0 0 0)]
           [max-v (make-vector 3 d-max)]
           [target (make-random-vector 3 0 d-max)]
           [fit-fn (lambda (p) (mm-distance p target))]
           [comp <]
           [neighs 5]
           [pop-per-neigh 20]
           [pop (initialize-population neighs pop-per-neigh min-v max-v fit-fn)]
           [inertia 0.8]
           [cognitive 0.8]
           [r1-min 0]
           [r1-max 1.0]
           [r2-min r23-min]
           [r2-max 1.0]
           [r3-min r23-min]
           [r3-max 1.0]
           [iters 3000000000])

      (run-swarm pop fit-fn comp neighs inertia cognitive neighw social r1-min r1-max r2-min r2-max r3-min r3-max iters))))

(define make-filename
  (lambda ()
    (let* ([d (current-date)]
           [y (date-year d)]
           [month (date-month d)]
           [day (date-day d)]
           [h (date-hour d)]
           [m (date-minute d)]
           [s (date-second d)])
      (format "~2,,,'0@s~2,,,'0@s~4,,,'0@s-~2,,,'0@s~2,,,'0@s~2,,,'0@s.dat" day month y h m s))))

;; generate a list of n evenly-spaced real values between min and max
;; truncates values to 3 decimal places
(define interpolate-values
  (lambda (n min-n max-n)
    (let ([incr (/ (exact->inexact (- max-n min-n)) n)])
      (let loop ([count 0])
        (if (= count n)
            `(,max-n)
            (cons (truncate-float (+ (* incr count) min-n) 3) (loop (add1 count))))))))

(define truncate-float
  (lambda (fl n)
    (/ (round (* (expt 10 n) fl)) (exact->inexact (expt 10 n)))))

(define run-experiments
  (lambda ()
    (let* ([neighws (interpolate-values 9 .1 1)]
           [socials neighws]
           [rand-floors (interpolate-values 10 -.8 .8)]
           [experiment-params (comb neighws socials rand-floors)]
           [runs-per-param 100]
           [max-eng-runs 20]
           [map-fn (lambda (params)
                     (let ([eng (make-engine (lambda () (apply run-single-experiment params)))])
                       (let loop ([i 0])
                         (if (< i runs-per-param)
                             (let ([complete (lambda (t v) (flush-output-port) (loop (add1 i)))])
                               (let run-loop ([this-eng eng] [eng-runs 0])
                                 (if (< eng-runs max-eng-runs)
                                     (let ([incomplete (lambda (inc-eng) (run-loop inc-eng (add1 eng-runs)))])
                                       (this-eng (most-positive-fixnum) complete incomplete))
                                     (printf "~f,~f,~f,~s\n" (car params) (cadr params) (caddr params) -1))))))))])
      (with-output-to-file (make-filename)
        (lambda () 
          (map map-fn experiment-params))))))
